home *** CD-ROM | disk | FTP | other *** search
- /*
- * This file is part of the portable Forth environment written in ANSI C.
- * Copyright (C) 1995 Dirk Uwe Zoller
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * This file is version 0.9.13 of 17-July-95
- * Check for the latest version of this package via anonymous ftp at
- * roxi.rz.fht-mannheim.de:/pub/languages/forth/pfe-VERSION.tar.gz
- * or sunsite.unc.edu:/pub/languages/forth/pfe-VERSION.tar.gz
- * or ftp.cygnus.com:/pub/forth/pfe-VERSION.tar.gz
- *
- * Please direct any comments via internet to
- * duz@roxi.rz.fht-mannheim.de.
- * Thank You.
- */
- /*
- * lined.c --- small general purpose line editor
- * (duz 08Jun93)
- */
-
- #include "forth.h"
- #include "support.h"
- #include "term.h"
- #include "lined.h"
-
- #include <string.h>
- #include <ctype.h>
-
- #include "missing.h"
-
- /* *INDENT-OFF* */
- static void left (int dist) { while (--dist >= 0) c_goleft (); }
- static void right (int dist) { while (--dist >= 0) c_goright (); }
- /* *INDENT-ON* */
-
- /* Some shortcuts. All functions in this file work on a "struct lined *l" */
- #undef MAX
-
- #define P (l->string)
- #define MAX (l->max_length)
- #define H (l->history)
- #define HMAX (l->history_max)
- #define L (l->length)
- #define C (l->cursor)
- #define HL (l->history_length)
- #define HR (l->history_read)
- #define HW (l->history_write)
-
- static void
- redisplay (struct lined *l)
- {
- int i;
-
- for (i = 0; i < L; i++)
- c_putc_printable (P[i]);
- left (i - C);
- }
-
- static void
- replace_string (struct lined *l, char *s)
- {
- int i;
-
- left (C);
- for (i = 0; *s && i < MAX; i++)
- c_putc_printable (P[i] = *s++);
- C = i;
- if (i < L)
- {
- for (; i < L; i++)
- c_putc (' ');
- left (i - C);
- }
- L = C;
- }
-
- static void
- put_history_string (struct lined *l, char *p)
- {
- char c;
-
- do
- {
- if (HL < HMAX)
- HL++;
- H[HW++] = c = *p++;
- HW %= HMAX;
- }
- while (c != '\0');
- HR = HW;
- }
-
- #define NEXT(X) (X = (X + 1) % HL)
- #define PREV(X) (X = (X + HL - 1) % HL)
-
- static int
- get_history_string (struct lined *l, char *p, int n)
- {
- int i, r = HR;
-
- for (i = 0; i < n; i++)
- {
- if (r == HW || (*p++ = H[r]) == '\0')
- break;
- NEXT (r);
- }
- return i;
- }
-
- static int
- back_history (struct lined *l)
- {
- char buf[0x100];
- int n = HR;
-
- if (HL == 0)
- return 0;
- PREV (n);
- do
- {
- PREV (n);
- if (n == HW)
- return 0;
- }
- while (H[n] != '\0');
- NEXT (n);
- HR = n;
- get_history_string (l, buf, sizeof buf);
- replace_string (l, buf);
- return 1;
- }
-
- static int
- fwd_history (struct lined *l)
- {
- char buf[0x100];
- int r = HR;
-
- if (HL == 0)
- return 0;
- for (r = HR; H[r] != '\0'; NEXT (r));
- NEXT (r);
- if (HR == HW)
- return 0;
- HR = r;
- get_history_string (l, buf, sizeof buf);
- replace_string (l, buf);
- return 1;
- }
-
- static void
- insertc (struct lined *l, char c)
- {
- int i;
-
- if (l->overtype)
- {
- if (C == L)
- L++;
- }
- else
- for (i = L++; i > C; i--)
- P[i] = P[i - 1];
- c_putc_printable (P[C++] = c);
- if (l->overtype)
- return;
- for (i = C; i < L; i++)
- c_putc_printable (P[i]);
- left (L - C);
- }
-
- int
- lined (struct lined *l, char *dflt)
- {
- char *b, buf[0x100]; /* scratchpad to work on */
- int c, i, display = 0;
-
- b = P, P = buf; /* switch to scratchpad */
- C = L = 0;
- if (dflt)
- replace_string (l, dflt);
- while (L < MAX)
- {
- c = getekey ();
- if (l->caps)
- c = change_case (c);
- switch (c)
- {
- case 'P' - '@':
- c = c_getkey ();
- if (l->caps)
- c = change_case (c);
- default:
- if (c >= 0x100) /* other function key */
- {
- if (!l->executes || c < EKEY_k1 || EKEY_k0 < c)
- {
- c_bell ();
- break;
- }
- right (L - C);
- c_puts ("\\\n");
- l->executes[c - EKEY_k1] (c - EKEY_k1);
- for (i = 0; i < L; i++)
- c_putc_printable (P[i]);
- left (L - C);
- break;
- }
- if (dflt)
- replace_string (l, "");
- insertc (l, c);
- break;
- case '\t':
- #if !NO_COMPLETION
- if (l->complete)
- {
- char cpl[0x100];
-
- store_c_string (P, C, cpl, sizeof cpl);
- if (display)
- {
- extern void cr_ (void);
-
- cr_ ();
- c = l->complete (cpl, cpl, 1);
- cr_ ();
- redisplay (l);
- }
- else
- {
- c = l->complete (cpl, cpl, 0);
- display = 1;
- }
-
- if (c == 0)
- {
- c_bell ();
- continue;
- }
- for (i = C; i < strlen (cpl); i++)
- insertc (l, cpl[i]);
- if (c == 1)
- insertc (l, ' ');
- else
- c_bell ();
- continue;
- }
- #endif
- do
- if (C < L && l->overtype)
- ++C, c_goright ();
- else
- insertc (l, ' ');
- while (C % 8 != 0);
- break;
- case 'D' - '@':
- case EKEY_kr:
- if (C == L)
- {
- c_bell ();
- break;
- }
- c_goright ();
- C++;
- break;
- case 'S' - '@':
- case EKEY_kl:
- if (C == 0)
- {
- c_bell ();
- break;
- }
- c_goleft ();
- C--;
- break;
- case 'A' - '@':
- while (C && P[C - 1] == ' ')
- c_goleft (), C--;
- while (C && P[C - 1] != ' ')
- c_goleft (), C--;
- break;
- case 'F' - '@':
- while (C < L && P[C] != ' ')
- c_goright (), C++;
- while (C < L && P[C] == ' ')
- c_goright (), C++;
- break;
- case EKEY_kb:
- case '\x7F':
- case 'H' - '@':
- if (C == 0)
- {
- c_bell ();
- break;
- }
- C--;
- c_goleft ();
- if (l->overtype)
- {
- c_putc_printable (P[C] = ' ');
- c_goleft ();
- break;
- }
- case EKEY_kD:
- case 'G' - '@':
- if (C == L)
- {
- c_bell ();
- break;
- }
- for (i = C; ++i < L;)
- c_putc_printable (P[i - 1] = P[i]);
- c_putc_printable (' ');
- left (i - C);
- L--;
- break;
- case EKEY_kI:
- case 'V' - '@':
- l->overtype = !l->overtype;
- continue;
- case 'C' - '@':
- l->caps = !l->caps;
- continue;
- case EKEY_ku:
- case 'E' - '@':
- if (!H || !back_history (l))
- c_bell ();
- break;
- case EKEY_kd:
- case 'X' - '@':
- if (!H || !fwd_history (l))
- c_bell ();
- break;
- case EKEY_kh:
- left (C);
- C = 0;
- break;
- case EKEY_kH:
- right (L - C);
- C = L;
- break;
- case 'Q' - '@':
- switch (toupper (c_getkey ()) | '@')
- {
- case 'S':
- left (C);
- C = 0;
- break;
- case 'D':
- right (L - C);
- C = L;
- break;
- default:
- c_bell ();
- }
- break;
- case 'U' - '@':
- replace_string (l, "");
- return 0;
- case 'J' - '@':
- case 'M' - '@':
- /* case EKEY_enter:
- */ goto end;
- }
- display = 0;
- dflt = NULL;
- }
- end:
- right (L - C);
- P[L] = '\0';
- if (H && L > 0)
- put_history_string (l, P);
- memcpy (b, P, L + 1); /* copy scratchpad to output string */
- P = b; /* restore pointer to original area */
- return 1;
- }
-